#include "drv_usb2uart.h"

uint8_t usart_rx_buffer[2][USART_BUFFER_SIZE];

void usart_send_data(uint8_t *send_data, uint16_t len, uint8_t cdc_id)
{
    uint16_t index = 0;
    usart_type *id = (cdc_id == 0) ? USB2UART_PORT : USB2UART2_PORT;
    
    for (index = 0; index < len; index++) {
        do {
            ;
        } while (usart_flag_get(id, USART_TDBE_FLAG) == RESET);
        usart_data_transmit(id, send_data[index]);
    }
}

void uartx_preinit(void)
{
    gpio_init_type gpio_init_struct;

    /* enable the usart2 and gpio clock */
    crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

    gpio_default_para_init(&gpio_init_struct);
    /* configure the usart2 tx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_2;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);

    /* configure the usart2 rx pin */
    gpio_init_struct.gpio_pins = GPIO_PINS_3;
    gpio_init(GPIOA, &gpio_init_struct);

    /* configure usart2 param */
    usart_init(USB2UART_PORT, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(USB2UART_PORT, TRUE);
    usart_receiver_enable(USB2UART_PORT, TRUE);
    //usart_dma_transmitter_enable(USB2UART_PORT, TRUE);
    usart_dma_receiver_enable(USB2UART_PORT, TRUE);
    usart_enable(USB2UART_PORT, TRUE);

    dma_init_type dma_init_struct;
    /* enable dma1 clock */
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    dma_reset(DMA1_CHANNEL1);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = USART_BUFFER_SIZE;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t) usart_rx_buffer[0];
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t) &USB2UART_PORT->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA1_CHANNEL1, &dma_init_struct);
    dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_UART2_RX);
    dma_channel_enable(DMA1_CHANNEL1, TRUE);
}

void uartx2_preinit(void)
{
    gpio_init_type gpio_init_struct;

    /* enable the usart3 and gpio clock */
    crm_periph_clock_enable(CRM_USART3_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

    gpio_default_para_init(&gpio_init_struct);
    /* configure the usart3 tx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = GPIO_PINS_10;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOB, &gpio_init_struct);

    /* configure the usart3 rx pin */
    gpio_init_struct.gpio_pins = GPIO_PINS_11;
    gpio_init(GPIOB, &gpio_init_struct);

    /* configure usart3 param */
    usart_init(USB2UART2_PORT, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(USB2UART2_PORT, TRUE);
    usart_receiver_enable(USB2UART2_PORT, TRUE);
    //usart_dma_transmitter_enable(USB2UART_PORT, TRUE);
    usart_dma_receiver_enable(USB2UART2_PORT, TRUE);
    usart_enable(USB2UART2_PORT, TRUE);

    dma_init_type dma_init_struct;
    /* enable dma1 clock */
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    dma_reset(DMA1_CHANNEL2);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = USART_BUFFER_SIZE;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t) usart_rx_buffer[1];
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t) &USB2UART2_PORT->dt;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA1_CHANNEL2, &dma_init_struct);
    dma_flexible_config(DMA1, FLEX_CHANNEL2, DMA_FLEXIBLE_UART3_RX);
    dma_channel_enable(DMA1_CHANNEL2, TRUE);
}

void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_coding, uint8_t cdc_id)
{
    usart_stop_bit_num_type usart_stop_bit = USART_STOP_1_BIT;
    usart_data_bit_num_type usart_data_bit = USART_DATA_8BITS;
    usart_parity_selection_type usart_parity_select = USART_PARITY_NONE;

    /* stop bit */
    switch (line_coding->bCharFormat)
    {
        case 0x0:
            usart_stop_bit = USART_STOP_1_BIT;
            break;
        /* to be used when transmitting and receiving data in smartcard mode */
        case 0x1:
            usart_stop_bit = USART_STOP_1_5_BIT;
            break;
        case 0x2:
            usart_stop_bit = USART_STOP_2_BIT;
            break;
        default:
            break;
    }
    switch (line_coding->bDataBits)
    {
        /* hardware usart not support data bits for 5/6 */
        case 0x5:
        case 0x6:
        case 0x7:
            break;
        case 0x8:
            usart_data_bit = USART_DATA_8BITS;
            break;
        /* hardware usart not support data bits for 16 */
        case 0x10:
            break;
        default:
            break;
    }
    /* parity */
    switch (line_coding->bParityType)
    {
        case 0x0:
            usart_parity_select = USART_PARITY_NONE;
            break;
        case 0x1:
            usart_parity_select = USART_PARITY_ODD;
            break;
        case 0x2:
            usart_parity_select = USART_PARITY_EVEN;
            break;
        /* hardware usart not support partiy for mark and space */
        case 0x3:
        case 0x4:
            break;
        default:
            break;
    }

    if (usart_parity_select == USART_PARITY_NONE)
    {
        usart_data_bit = USART_DATA_8BITS;
    }
    else
    {
        usart_data_bit = USART_DATA_9BITS;
    }

    if(cdc_id == 0)
    {
        usart_init(USB2UART_PORT, line_coding->dwDTERate, usart_data_bit, usart_stop_bit);
        usart_parity_selection_config(USB2UART_PORT, usart_parity_select);
    }
    else
    {
        usart_init(USB2UART2_PORT, line_coding->dwDTERate, usart_data_bit, usart_stop_bit);
        usart_parity_selection_config(USB2UART2_PORT, usart_parity_select);
    }
}
